解析の基礎/演習2
いよいよ解析の本番だ。
すでにデバッグ画面を見ているからわかるとは思うが、MessageBox が3つあるな?
この演習プログラムでの目的はこれら3つの MessageBox を全てを表示させることだ。
だが、単純に表示させるだけでは意味が無いから制限を設けようか。
ルール:ZFフラグ(ゼロフラグ)を直にいじくらない。
だ。
さて、まずは実行してみようか。MessageBox が出てくるところまでは前回と同じだ。
次の MessageBox までの命令文を見てみると以下のようになっている。
00401019 . 31C0 XOR EAX,EAX
0040101B . 85C0 TEST EAX,EAX
0040101D . 75 01 JNZ SHORT base_tes.00401020
0040101F . C3 RETN
まずは xor eax, eax だ、xor は 排他的論理和をとる。
つまり同じ値同士であれば、ゼロにするという処理になる。この例では eax と eax の xor をとっているが
これはゼロクリアをする際によく使われる手段だ。
F8 で xor eax, eax まで進めてみようか。右上の eax には 1 が入っているはずだ。
そしてこの命令を実行することにより、eax に入っていた値(1)はゼロとなる。
ここでひとつ教えておこう、いつの間に eax には 1 が入ったのか? 前回の説明では伝えていなかったが、
API の処理が成功するとゼロ以外の値が戻り値として返される。
返却先は eax だ。これには例外は無い。よって今回の場合は、事前に実行された MessageBox の処理が正常に
終了したため、ゼロ以外の戻り値が eax に収められたというわけだ。
それでは再度 F8 で eax の値がゼロになるのを確認してくれ。
次は test eax, eax の処理だ。
これは論理積の演算をする。つまり AND と同じだな。これは条件ジャンプ命令の判定として使われることがある。
ここでは事前に eax をゼロクリアしている。そのため AND をとってもゼロとなる。
つまり ZFフラグ(ゼロフラグ)が ON(1)になってしまう。これによりどのような影響がでるのか?がキーだ。
そう、次の命令 JNZ に関係してくる。
JNZ は ZFフラグ(ゼロフラグ)が 1 でなければ飛ぶ命令だ。よって今回のように1がたっている場合は飛ばないわけだ。
ちなみに飛ぶ場合はもちろん MessageBox に飛ぶようになる。
0040101D . 75 01 JNZ SHORT base_tes.00401020 ⇒ アドレス00401020へ飛ぶ
.
.
00401020 > 68 05000000 PUSH 5 ; /Style = MB_RETRYCANCEL|MB_APPLMODAL
00401025 . 68 12204000 PUSH base_tes.00402012 ; |Title = "MessageBox2"
0040102A . 68 1E204000 PUSH base_tes.0040201E ; |Text = "Second"
0040102F . 68 00000000 PUSH 0 ; |hOwner = NULL
00401034 . E8 C71F0000 CALL ; \MessageBoxA
さて、Ollydbg の右上にレジスタの情報が載っているのはもう確認したな?
確かにそこの「Z 1」の 1 をクリックすれば値を変更することは可能だ。
しかし、ルールを設けたのを覚えているな?ではゼロにしないようにするには?
わかっているとは思うがゼロにしなきゃいい。
つまり、ゼロにさせられる処理内容を変えてしまえばいい。ということだ。
ここで考えられる方法は xor の演算対象を変えることだ、プログラムの処理を変更・修正するにはデバッグ画面上で
変更したい処理をダブルクリックすれば書き換えることができる。
あえて答えは書かないが、xor が具体的にどのような処理をするか分からないみじんこは 2日目の基礎知識の内容を
よく読んで考えてみろ。自分で考える力の無い物はミジンコゼミを卒業しても何もできずじまいだ。
そして xor をはじめとして and や or も今後、自分の力で解析や開発をやりたいなら必ず理解しておかなければならない命令群だ!
では Messagebox の2つめだけ表示できたみじんこから次に最後にいくぞ。
2つめの MessageBox が表示されると「再試行」と「キャンセル」の二つが選べるようになっている。
とりあえず「再試行」でも選んでみるか。
00401020 > 68 05000000 PUSH 5 ; /Style = MB_RETRYCANCEL|MB_APPLMODAL
00401025 . 68 12204000 PUSH base_tes.00402012 ; |Title = "MessageBox2"
0040102A . 68 1E204000 PUSH base_tes.0040201E ; |Text = "Second"
0040102F . 68 00000000 PUSH 0 ; |hOwner = NULL
00401034 . E8 C71F0000 CALL ; \MessageBoxA
00401039 . 3C 04 CMP AL,4
0040103B . 75 1B JNZ SHORT base_tes.00401058
0040103D . C3 RETN
「再試行」を選んだあとに処理をみてみるとアドレス 00401039 の処理で AL と 4 を比較しているのが確認できる。
さらにその下にはまたもや JNZ 命令がある。
つまり、cmp 命令の比較結果がゼロじゃなければ飛ぶ。というわけだ。もしゼロだった場合はゼロフラグが1となり、
JNZ の条件には一致しないため処理は終了となる。
さて、右上のレジスタウィンドウを見てみると EAX は見事に4だ。つまり比較をした結果、見事にゼロフラグが
立ってしまったわけだ。
このままだと飛んでしまうわけだが、もしもゼロフラグがたたずに JNZ 命令で飛ぶことができたらどうなっていたのだろうか?
実はこれも確認ができる。Ollydbg のデバッグ画面で JNZ の処理をクリックし、Enter をしてみろ。
見事に JNZ が指し示すアドレス 00401058 へ飛んだはずだ。
※ あくまで表示上だけで実際のプログラム処理は行われない
ではここで飛んだら本当に MessageBox が表示されるのか追ってみるぞ。
まずはここでアドレス 00401058 の処理へ飛ぶ。
0040103B . 75 1B JNZ SHORT base_tes.00401058
飛んだ先ではまたもや比較をしているが、「再試行」のときは 4 と比較していたことを考えると
「キャンセル」を選んだ場合には AL に 2 が格納されていると推測ができる。
その結果として 次は 00401060 に飛ぶようだ。
00401058 > 3C 02 CMP AL,2
0040105D . 74 01 JE SHORT base_tes.00401060
さて、ここまで飛んできたがなにやらスタックにデータを入れているようだ。
よく見てみるとモジュールエントリーポイントとじゃないか!
これはこのプログラムの一番最初をさしている。つまり、この処理を行うとプログラムの一番最初に戻ってしまうということだ!
な、なんだt(AA略
00401060 > 68 00104000 PUSH base_tes.<モジュールエントリーポイント>
00401065 . C3 RETN ; RET used as a jump to <モジュールエントリーポイント>
ではここまでで分かったことをまとめておこう。
2つ目の MessageBox で「再試行」を選ぶと AL には 4が戻り値として入り、プログラムが終了する。
逆に「キャンセル」を選ぶと AL には 2が入りプログラムが終了しないものの、一番最初の処理に戻ってしまう。
つまりどちらを選んでも MessageBox の3つ目は表示されないということだ。
しかしどうしても 3つ目の MessageBox を表示させなければいけない。何かいい方法はないだろうか?
ここで考えるべきは 3つ目の MessageBox へ飛ぶには何が必要か?だ、
「再試行」「キャンセル」のいづれも選んでもほかの処理に飛んでしまう
飛んでしまう・・・
そう、飛んでしまえばいいのだ。
いかにみじんこでもさすがに分かっただろう。
「再試行」「キャンセル」のどちらでも MessageBox に飛ぶようにしてしまえばいいのだ。
つまりジャンプする先の書き換えである。
それに必要なのは3つ目の MessageBox のアドレスだけだ。
0040103E . 68 00000000 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
00401043 . 68 25204000 PUSH base_tes.00402025 ; |Title = "MessageBox3"
00401048 . 68 31204000 PUSH base_tes.00402031 ; |Text = "Last"
0040104D . 68 00000000 PUSH 0 ; |hOwner = NULL
00401052 . E8 A91F0000 CALL ; \MessageBoxA
3つ目の MessageBox のアドレスは 0040103E から始まっている。
さて、最後は「再試行」「キャンセル」の判定の後の jne 命令および飛び先のアドレスを書き換えれば終了だ。
書き換えた後は「右クリック」⇒「実行ファイルへコピー」⇒「全ての変更箇所」をクリックしろ。
ポップアップが出たら「全てコピー」を選択し、プログラム上のアドレスを表示する窓がでるが閉じて上書き保存しろ。
これで全て終了だ。
次はいよいよ実践の基礎を行うぞ 多重起動1に移動して用意しておけ
|